package cn.gs.db;

import java.io.Serializable;
import java.util.*;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;

/**
 * Hibernate Utility class with a convenient method to get Session Factory
 * object.
 *
 * @author gs
 */
public class HibernateUtil {

    public static final int TRANSACTION_TIMEOUT = 3;
    private Session session;
    private final SessionFactory sessionFactory;

    public HibernateUtil() {
        Configuration cfg = new Configuration();
        sessionFactory = cfg.configure().buildSessionFactory(/*
                 * new
                 * ServiceRegistryBuilder().configure().buildServiceRegistry()
                 */);
        session = sessionFactory.openSession();
    }

    public HibernateUtil(String path) {
        Configuration cfg = new Configuration();
        sessionFactory = cfg.configure(path).buildSessionFactory(/*
                 * new
                 * ServiceRegistryBuilder().configure().buildServiceRegistry()
                 */);
        session = sessionFactory.openSession();
    }

    public Object transaction(ObjectTransaction t) throws RuntimeException {
        begin();
        try {
            Object b = t.work();
            commit();
            return b;
        } catch (RuntimeException ex) {
            rollback();
            throw ex;
        }
    }

    public boolean transaction(BoolTransaction t) throws RuntimeException {
        long bg = System.currentTimeMillis();
        begin();
        try {
            boolean b = t.work();
            if (b) {
                commit();
                System.out.println("hibernate:Commit" + (System.currentTimeMillis() - bg));
            } else {
                rollback();
                System.out.println("hibernate:Rollback" + (System.currentTimeMillis() - bg));
            }
            return b;
        } catch (RuntimeException ex) {
            rollback();
            System.out.println("hibernate:Err" + (System.currentTimeMillis() - bg));
            throw ex;
        }
    }

    public void transactionSaveOrUpdate(Object... os) {
        begin();
        try {
            for (Object o : os) {
                saveOrUpdate(o);
            }
            commit();
        } catch (RuntimeException ex) {
            rollback();
            throw ex;
        }
    }

    public void begin() {
        Transaction t = getSession().beginTransaction();
        t.setTimeout(TRANSACTION_TIMEOUT);
    }

    public void commit() {
        getSession().getTransaction().commit();
    }

    public void rollback() {
        getSession().getTransaction().rollback();
    }

    public Query query(String s) {
        return getSession().createQuery(s);
    }

    public Query query(String s, Object args) {
        Query q = query(s);
        q.setProperties(args);
        return q;
    }

    public Query query(String s, Map args) {
        Query q = query(s);
        q.setProperties(args);
        return q;
    }

    public int execute(String s) {
        Query q = query(s);
        return q.executeUpdate();
    }

    public int executeSQL(String s) {
        Query q = getSession().createSQLQuery(s);
        return q.executeUpdate();
    }

    public Object uniqueResult(String s) {
        Query q = getSession().createQuery(s);
        return q.uniqueResult();
    }

    public void saveOrUpdate(Collection items) {
        for (Object t : items) {
            getSession().saveOrUpdate(t);
        }
    }

    public synchronized void saveOrUpdate(Object... os) {
        saveOrUpdate(Arrays.asList(os));
    }

    public void delete(Collection items) {
        for (Object t : items) {
            getSession().delete(t);
        }
    }

    public synchronized void delete(Object... os) {
        delete(Arrays.asList(os));
    }

    public <T> List<T> get(Class<T> clazz, List<? extends Serializable> ids) {
        List<T> list = new LinkedList<T>();
        for (Serializable id : ids) {
            T t = (T) getSession().get(clazz, id, LockOptions.UPGRADE);
            list.add(t);
        }
        return list;
    }

    public <T> T get(Class<T> clazz, Serializable id) {
        return (T) getSession().get(clazz, id, LockOptions.UPGRADE);
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    //ThreadLocal<Session> sessions = new ThreadLocal<Session>();

    public Session getSession() {
//        Session s = sessions.get();
//        if (null == s) {
//            s = getSessionFactory().openSession();
//            sessions.set(s);
//        }
//        return s;
        return getSessionFactory().getCurrentSession();
    }
}
